package ru.hh.team02.chat.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;


public class ChatServer {
    private static final int PORT = 2004;
    
    private static final int MAX_THREADS = 100;
    private static final Executor executor = 
            Executors.newFixedThreadPool(MAX_THREADS);
    private static final MessageSender messageSender = 
            new MessageSender();
    
    ServerSocket listener;
    
    // множество потоков ввода для сокетов всех текущих клиентов (т.е. куда им писать)
    // обязательно надо менять на что то потокобезопасное
    private static HashSet<PrintWriter> writers = new HashSet<PrintWriter>();
    
    public static void start() {
        ChatServer server = new ChatServer(); 
        server.run();
    }
    
    /*
     * listens to a port and spawns handlers
     */
    private void run() {
        try {
            listener = new ServerSocket(PORT);
            System.out.println("waiting for connection...");
            while (true) {
                try  {
                    final Socket connection = listener.accept();
                    executor.execute(new Handler(connection));      
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                listener.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    /*
     * task, which hangs on client socket and listens to it
     */
    private static class Handler implements Runnable {
        private StringSocket socket;
        
        public Handler(Socket socket) {
            this.socket = new StringSocket(socket);
        }

        @Override
        public void run() {
            try {      
                socket.openStreams();
                socket.write("connected");
                synchronized(ChatServer.writers) {
                    ChatServer.writers.add(socket.getWriter());
                }
                
                String message = "";
                do {
                    message = socket.read();
                    handleMessage(message);
                } while (!message.equals("bye"));
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                ChatServer.writers.remove(socket.getWriter());
                socket.close();
            }
        }
        
        /*
         * puts message in the queue
         */
        private void handleMessage(String message) {
            System.out.println(message);
            
            synchronized(ChatServer.writers) {
                for (PrintWriter p : ChatServer.writers) {
                    if (p != socket.getWriter()) {
                        ChatServer.messageSender.addMessage(
                                new Message(message, p));
                    }
                }
            }
        }
    }
}
